home *** CD-ROM | disk | FTP | other *** search
/ System Booster / System Booster.iso / Commodities / BlackHole / Source / blackhole.c next >
Encoding:
C/C++ Source or Header  |  1996-09-27  |  21.9 KB  |  812 lines

  1.  
  2. /*
  3.  * Blackhole.c -- File deletion tool. When run, it puts an appicon on the WB
  4.  * screen. Any icons that are dropped on the appicon are deleted.
  5.  * $Revision: 1.32
  6.  */
  7.  
  8. #include "header.h"
  9. #include "prog-protos.h"
  10.  
  11. /* Prototypes */
  12. Prototype BOOL is_mine (char *);
  13. Prototype void save_prefs (void);
  14. Prototype LONG get_limit (void);
  15. Prototype void snapshot (LONG , LONG );
  16. Prototype void read_prefs (void);
  17. Prototype void allow_request (BOOL );
  18. Prototype char *safecat (char *, char *, int );
  19. Prototype LONG set_current (struct WBArg *, int );
  20. Prototype LONG error_request (char *, char *);
  21. Prototype BOOL user_request (LONG );
  22. Prototype void fail_request (char *);
  23. Prototype void get_tooltypes (struct DiskObject *);
  24.  
  25. Local void wbmain (struct WBStartup *);
  26. Local void copy_and_add (struct List *, int , struct WBArg *);
  27. Local void delete_next (struct List *);
  28. Local LONG add_WBArg_to_List (struct WBArg *, struct List *);
  29. Local BOOL confirm_deletion (struct List *);
  30. Local void scrub (struct DiskObject *);
  31. Local struct HoleArg *create_arg (void);
  32. Local void free_arg (struct HoleArg *);
  33. Local void free_list (struct List *);
  34. Local void handle_messages (struct List *);
  35. Local int main (int , char **);
  36.  
  37. /* Shared Variables */
  38. Prototype struct IntuitionBase *IntuitionBase;
  39.  
  40. /* Globals */
  41. static const struct HolePrefs defaultprefs =
  42. {
  43.     FALSE,    /* Ignore protection == FALSE */
  44.     TRUE,    /* confirm == TRUE */
  45.     15,     /* DeleteLimit */
  46.     NO_ICON_POSITION,
  47.     NO_ICON_POSITION
  48. };
  49. static const char *memfail = "Out of memory.";
  50.  
  51. struct HolePrefs currprefs; /* current preferences, copied into HoleArgs for use */
  52.  
  53. struct IntuitionBase *IntuitionBase = NULL;
  54. struct WorkbenchBase *WorkbenchBase = NULL;
  55. struct IconBase      *IconBase        = NULL;
  56. struct CxBase         *CxBase        = NULL;
  57. struct GadToolsBase  *GadToolsBase  = NULL;
  58. struct WBArg         *start_icon    = NULL; /* name of icon we started from */
  59. struct MsgPort         *appmsgport    = NULL; /* AppIcon Message port */
  60. struct DiskObject    *myicon        = NULL; /* The icon we have been started from */
  61.  
  62. APTR old_window_ptr = NULL;    /* For allow_request */
  63. struct EasyStruct error_req =
  64. {
  65.     sizeof (struct EasyStruct),
  66.     0,
  67.     "Black Hole",
  68.     NULL,
  69.     NULL,
  70. };
  71.  
  72. BYTE *version = "$VER: BlackHole v1.1 " __DATE__;
  73. #define ABOUT_STRING "BlackHole v1.1\n" __DATE__ "\nby Alan Singfield"
  74. #define NUMBER_OF_MY_TOOLTYPES 5
  75.  
  76. #define CURR_SIZE 255
  77. char current [CURR_SIZE+1];    /* current file we are working on */
  78.  
  79. #ifdef DEBUG
  80. #define D(x) x
  81. #define bug printf
  82. #else
  83. #define D(x) ;
  84. #endif
  85.  
  86. /* Functions */
  87. void wbmain (struct WBStartup *wbs)
  88. {
  89.     struct AppIcon *appicon = NULL;    /* The AppIcon itself */
  90.     struct List *list = NULL; /* list of files to delete */
  91.     BPTR olddir = NULL;
  92.  
  93.     unless (IntuitionBase = (struct IntuitionBase *)
  94.     OpenLibrary("intuition.library", 37))
  95.     {
  96.     fail_request ("Black Hole requires\nIntuition library v37\n or greater.");
  97.     goto fail;
  98.     }
  99.  
  100.     unless (WorkbenchBase = (struct WorkbenchBase *)
  101.     OpenLibrary("workbench.library", 37))
  102.     {
  103.     fail_request ("Black Hole requires\nWorkbench library v37\n or greater.");
  104.     goto fail;
  105.     }
  106.  
  107.     unless (IconBase = (struct IconBase *) OpenLibrary ("icon.library", 37))
  108.     {
  109.     fail_request ("Black Hole requires\nIcon library v37\n or greater.");
  110.     goto fail;
  111.     }
  112.  
  113.     unless (CxBase = (struct CxBase *) OpenLibrary ("commodities.library", 37))
  114.     {
  115.     fail_request ("Black Hole requires\nCommodities library v37\n or greater.");
  116.     goto fail;
  117.     }
  118.  
  119.     unless (GadToolsBase = (struct GadToolsBase *)
  120.     OpenLibrary ("gadtools.library", 37))
  121.     {
  122.     fail_request ("Black Hole requires\nGadTools library v37\n or greater.");
  123.     goto fail;
  124.     }
  125.  
  126.     start_icon = &(wbs->sm_ArgList[0]);    /* put name of icon into global */
  127.     olddir = CurrentDir (start_icon->wa_Lock);
  128.  
  129.     unless (myicon = GetDiskObjectNew (start_icon->wa_Name))
  130.     {
  131.     fail_request ("Cannot open file\nBlackHole.info");
  132.     goto fail;
  133.     }
  134.     get_tooltypes (myicon); /* get user preferences from tooltypes */
  135.     scrub (myicon);   /* Remove all the extraneous data from the DiskObject */
  136.  
  137.     unless (appmsgport = CreateMsgPort())
  138.     {
  139.     fail_request ("MsgPort not opened!");
  140.     goto fail;
  141.     }
  142.  
  143.     unless (appicon = AddAppIcon (NULL, NULL, wbs->sm_ArgList[0].wa_Name,
  144.     appmsgport, NULL, myicon, NULL))
  145.     {
  146.     fail_request ("Could not put AppIcon\non Workbench screen!");
  147.     goto fail;
  148.     }
  149.  
  150.     unless (list = malloc (sizeof (struct List)))
  151.     {
  152.     fail_request (memfail);
  153.     goto fail;
  154.     }
  155.     NewList (list); /* Intialise the list */
  156.  
  157.     handle_messages (list); /* The main bit!        */
  158.  
  159.     fail:                /* This is the tidy up section        */
  160.  
  161.     if (list)
  162.     {
  163.     free_list (list);
  164.     free (list);
  165.     }
  166.     if (appicon)
  167.     {
  168.     struct Message *mess;
  169.  
  170.     Forbid();                       /* strip messages under Forbid()    */
  171.     while (mess = GetMsg (appmsgport)) ReplyMsg (mess);
  172.     RemoveAppIcon (appicon);
  173.     Permit();
  174.     }
  175.     if (appmsgport)     DeleteMsgPort   (appmsgport);
  176.     if (myicon)         FreeDiskObject  (myicon);
  177.     if (olddir)         CurrentDir      (olddir);
  178.     if (GadToolsBase)   CloseLibrary    (GadToolsBase);
  179.     if (CxBase)         CloseLibrary    (CxBase);
  180.     if (IconBase)       CloseLibrary    (IconBase);
  181.     if (WorkbenchBase)  CloseLibrary    (WorkbenchBase);
  182.     if (IntuitionBase)  CloseLibrary    (IntuitionBase);
  183. }
  184.  
  185. /* In case anyone tries to run us from the CLI */
  186. int main (int argc, char **argv)
  187. {
  188.     printf ("Run me from my icon, please!\n");
  189.     return (10);
  190. }
  191.  
  192. void fail_request (char *text)
  193. {
  194.     error_request (text, "OK");
  195. }
  196.  
  197. LONG error_request (char *text, char *gadget)
  198. {
  199.     struct Screen *psc;
  200.     struct Window *window = NULL;
  201.     int rc;
  202.  
  203.     if (psc = LockPubScreen ("Workbench")) window = psc->FirstWindow;
  204.  
  205.     error_req.es_GadgetFormat = gadget;
  206.     error_req.es_TextFormat = text;
  207.  
  208.     rc = EasyRequest (window, &error_req, 0, "");
  209.  
  210.     if (psc) UnlockPubScreen (NULL, psc);
  211.  
  212.     return (rc);
  213. }
  214.  
  215. /* set_current -- update a global buffer current[] with the name of the file */
  216. /* that is currently being worked on. (Used for error messages)              */
  217.  
  218. LONG set_current (struct WBArg *wa, int mode)
  219. {
  220.     char buf[CURR_SIZE+1];  /* temporary buffer for filenames */
  221.     char *end;            /* pointer to a character found by FilePart */
  222.  
  223.     switch (mode)
  224.     {
  225.     case SET_START:
  226.     strcpy (current, "");   /* reset current */
  227.     break;
  228.  
  229.     case SET_NEWFILE:
  230.     unless (wa) return (ERROR_OBJECT_WRONG_TYPE);
  231.     if ((wa->wa_Name[0] == 0) || !wa->wa_Name)  /* is it a dir? */
  232.     {
  233.         if (!NameFromLock (wa->wa_Lock, buf, CURR_SIZE)) return (IoErr());
  234.         if (buf [strlen(buf)-1] == ':') /* is it a disk? */
  235.         {
  236.         sprintf (current, "%s", buf);
  237.         return (ERROR_OBJECT_WRONG_TYPE);
  238.         }
  239.         AddPart (current, FilePart (buf), CURR_SIZE);   /* put name of dir into current */
  240.         strcat (current, "/");
  241.     }
  242.     else        /* must be a file */
  243.     {
  244.         end = FilePart (current);
  245.         *end = NULL;    /* remove filename */
  246.         AddPart (current, wa->wa_Name, CURR_SIZE);
  247.     }
  248.     break;
  249.  
  250.     case SET_EXIT_DIR:    /* exit one directory level */
  251.     end = PathPart (current);
  252.     *end = NULL;
  253.     break;
  254.     }
  255.     return (0);
  256. }
  257. void get_tooltypes (struct DiskObject *dob)
  258. {
  259.     char **tt = dob->do_ToolTypes;
  260.  
  261.     currprefs = defaultprefs;     /* Aren't structure assigns excellent? */
  262.  
  263.     if (FindToolType (tt, "IGNOREPROTECTION")) currprefs.ignore_prot = TRUE;
  264.     if (FindToolType (tt, "DONOTCONFIRM")) currprefs.confirm = FALSE;
  265.  
  266.     currprefs.CurrentX = ArgInt (tt, "ICONX", currprefs.CurrentX);
  267.     currprefs.CurrentY = ArgInt (tt, "ICONY", currprefs.CurrentY);
  268.     currprefs.deletelimit = ArgInt (tt, "DELETELIMIT", currprefs.deletelimit);
  269. }
  270.  
  271. /* Return TRUE if tooltype is one that Black Hole reads (e.g. ICONY) */
  272. BOOL is_mine (char *tooltype)
  273. {
  274.     if (!(stricmp (tooltype, "IGNOREPROTECTION"))) return (TRUE);
  275.     if (!(stricmp (tooltype, "(IGNOREPROTECTION)"))) return (TRUE);
  276.     if (!(stricmp (tooltype, "DONOTCONFIRM"))) return (TRUE);
  277.     if (!(stricmp (tooltype, "(DONOTCONFIRM)"))) return (TRUE);
  278.     if (!(strnicmp (tooltype, "ICONX", 5))) return (TRUE);
  279.     if (!(strnicmp (tooltype, "(ICONX", 6))) return (TRUE);
  280.     if (!(strnicmp (tooltype, "ICONY", 5))) return (TRUE);
  281.     if (!(strnicmp (tooltype, "(ICONY", 6))) return (TRUE);
  282.     if (!(strnicmp (tooltype, "DELETELIMIT", 11))) return (TRUE);
  283.     if (!(strnicmp (tooltype, "(DELETELIMIT", 12))) return (TRUE);
  284.  
  285.     return (FALSE);
  286. }
  287.  
  288. #define BUF_SIZE 80
  289. void save_prefs (void)
  290. {
  291.     read_prefs();
  292.  
  293.     struct DiskObject *dob = NULL;
  294.     BPTR olddir = NULL;
  295.     char **newtt = NULL;    /* new tooltypes created by me. */
  296.     int othercount = 0; /* Count of other tooltypes in icon (like DONOTWAIT, etc) */
  297.     int i;  /* general count variable */
  298.     BOOL success = FALSE;
  299.  
  300.     olddir = CurrentDir (start_icon->wa_Lock);
  301.     unless (dob = GetDiskObjectNew (start_icon->wa_Name)) goto fail;
  302.  
  303.     /* Count the tooltypes, excluding those we are going to remove */
  304.     for (i = 0; dob->do_ToolTypes[i]; i++)
  305.     {
  306.     unless (is_mine (dob->do_ToolTypes[i])) othercount++;
  307.     }
  308.  
  309.     /* Reserve the memory for the new tooltypes */
  310.     unless (newtt = calloc (sizeof (char *), NUMBER_OF_MY_TOOLTYPES + othercount+ 1)) goto fail;
  311.  
  312.     /* Copy old tooltypes to the new by duplicating, excluding any of mine */
  313.     int newcount = 0;
  314.     for (i=0; dob->do_ToolTypes[i]; i++)
  315.     {
  316.     unless (is_mine (dob->do_ToolTypes[i]))
  317.     {
  318.         unless (newtt [newcount++] = strdup (dob->do_ToolTypes[i])) goto fail;
  319.     }
  320.     }
  321.  
  322.     /* Now write in my tooltypes. */
  323.     char buf[BUF_SIZE];
  324.  
  325.     if (panel->prefs.CurrentX != NO_ICON_POSITION)
  326.     {
  327.     sprintf (buf, "ICONX=%d", panel->prefs.CurrentX);
  328.     }
  329.     else sprintf (buf, "(ICONX=0)");
  330.     unless (newtt [newcount++] = strdup (buf)) goto fail;
  331.  
  332.     if (panel->prefs.CurrentY != NO_ICON_POSITION)
  333.     {
  334.     sprintf (buf, "ICONY=%d", panel->prefs.CurrentY);
  335.     }
  336.     else sprintf (buf, "(ICONY=0)");
  337.     unless (newtt [newcount++] = strdup (buf)) goto fail;
  338.  
  339.     sprintf (buf, "DELETELIMIT=%d", panel->prefs.deletelimit);
  340.     unless (newtt [newcount++] = strdup (buf)) goto fail;
  341.  
  342.     if (panel->prefs.confirm) sprintf (buf, "(DONOTCONFIRM)");
  343.     else sprintf (buf, "DONOTCONFIRM");
  344.     unless (newtt [newcount++] = strdup (buf)) goto fail;
  345.  
  346.     if (panel->prefs.ignore_prot) sprintf (buf, "IGNOREPROTECTION");
  347.     else sprintf (buf, "(IGNOREPROTECTION)");
  348.     unless (newtt [newcount++] = strdup (buf)) goto fail;
  349.  
  350.     /* Now put new tooltypes into icon, and save it. */
  351.     dob->do_ToolTypes = newtt;
  352.  
  353.     unless (PutDiskObject (start_icon->wa_Name, dob)) goto fail;
  354.  
  355.     success = TRUE; /* We did it! */
  356.  
  357.     fail:   /* Now clean up */
  358.  
  359.     unless (success) fail_request ("Could not\nsave preferences");
  360.     if (newtt)
  361.     {
  362.     int i = 0;
  363.     while (newtt[i]) free (newtt[i++]);
  364.     free (newtt);
  365.     }
  366.     if (dob) FreeDiskObject (dob);
  367.     if (olddir) CurrentDir (olddir);
  368.  
  369. }
  370.  
  371. #undef BUF_SIZE
  372.  
  373. /* Read in the user preferences from the gadgets in the control panel */
  374. /* assumes panel is non-NULL */
  375. void read_prefs (void)
  376. {
  377.     panel->prefs.confirm = ((panel->gad_confirm->Flags & GFLG_SELECTED) != 0);
  378.     panel->prefs.ignore_prot = ((panel->gad_ignore_prot->Flags & GFLG_SELECTED) != 0);
  379.     panel->prefs.deletelimit = get_limit();
  380.     /* If value of panel's deletelimit is invalid, use the old one. */
  381.     if (panel->prefs.deletelimit < 1) panel->prefs.deletelimit = currprefs.deletelimit;
  382. }
  383.  
  384. /* Get the delete limit */
  385. LONG get_limit (void)
  386. {
  387.     struct StringInfo *si = (struct StringInfo *)panel->gad_limit->SpecialInfo;
  388.     return (si->LongInt);
  389. }
  390.  
  391. /* Snapshot the position of the appicon */
  392. void snapshot (LONG xpos, LONG ypos)
  393. {
  394.     panel->prefs.CurrentX = xpos;
  395.     panel->prefs.CurrentY = ypos;
  396.     if (xpos == NO_ICON_POSITION) fail_request ("Icon position\nforgotten.");
  397.     else fail_request ("Icon position\nrecorded.");
  398. }
  399.  
  400. void handle_messages (struct List *list)
  401. {
  402.     BOOL quitnow = FALSE;
  403.     LONG error;
  404.     int argnum;
  405.  
  406.     ULONG winmask;
  407.     ULONG appmask = 1<< appmsgport->mp_SigBit;
  408.  
  409.     repeat  /* until (quitnow) */
  410.     {
  411.     winmask = panel ? (1<< panel->window->UserPort->mp_SigBit) : 0;
  412.  
  413.     /* if there are no files to delete at the moment then Wait() */
  414.     if (IsListEmpty (list)) Wait (winmask | appmask);
  415.     else delete_next (list);
  416.  
  417.     /* Handle appmessages */
  418.     {
  419.         struct AppMessage *appmsg;
  420.         while (appmsg = (struct AppMessage *)GetMsg (appmsgport))
  421.         {
  422.         if (argnum = appmsg->am_NumArgs)
  423.         {
  424.             copy_and_add (list, argnum, appmsg->am_ArgList);
  425.         }
  426.         ReplyMsg ((struct Message *)appmsg);
  427.  
  428.         if (argnum == 0)    /* did the user double click on our appicon? */
  429.         {
  430.             /* Open control panel, or if already open, activate it */
  431.             unless (open_control_panel(&currprefs))
  432.             fail_request (memfail);
  433.         }
  434.         }
  435.     }
  436.  
  437.     struct IntuiMessage *intuimsg;
  438.     while (panel && (intuimsg = (struct IntuiMessage *)
  439.     GT_GetIMsg (panel->window->UserPort)))
  440.     {
  441.         /* It's always a gadget, and always an IDCMP_GADGETUP */
  442.         struct Gadget *gad = (struct Gadget *)intuimsg->IAddress;
  443.         GT_ReplyIMsg (intuimsg);
  444.  
  445.         switch (gad->UserData)
  446.         {
  447.         case GAD_SAVE:
  448.         save_prefs();
  449.                     /* No break! */
  450.         case GAD_USE:
  451.         read_prefs();
  452.         currprefs = panel->prefs;
  453.                     /* No break! */
  454.         case GAD_CANCEL:
  455.         close_control_panel();
  456.         break;
  457.  
  458.         case GAD_QUIT:
  459.         /* Assumes nothing else has caused quitnow to be true */
  460.         quitnow = error_request ("OK to quit?", "Yes|No");
  461.         break;
  462.  
  463.         case GAD_CONFIRM:
  464.         case GAD_IGNORE:
  465.         /* These need no action */
  466.         break;
  467.  
  468.         case GAD_LIMIT:
  469.         /* Check that limit value is valid */
  470.         if (get_limit() < 1)
  471.         {
  472.             DisplayBeep (NULL); /* flash the display */
  473.         }
  474.         break;
  475.  
  476.         case GAD_UNSNAP:
  477.         snapshot (NO_ICON_POSITION, NO_ICON_POSITION);
  478.         break;
  479.  
  480.         case GAD_SNAP:
  481.         /* This doesn't work!!! I hope Commodore patch AddAppIcon so it */
  482.         /* updates these fields in the near future. */
  483.         snapshot (myicon->do_CurrentX, myicon->do_CurrentY);
  484.         break;
  485.  
  486.         case GAD_ABOUT:
  487.         fail_request (ABOUT_STRING);
  488.         break;
  489.         }
  490.     }
  491.     } until (quitnow);
  492.  
  493.     close_control_panel();  /* Safe to call this even if panel is closed */
  494. }
  495.  
  496. /* Delete one file from list, which must not be empty. Tries to minimise disk */
  497. /* swapping by deleting those files that are available first.              */
  498. void delete_next (struct List *list)
  499. {
  500.     LONG error = 0;
  501.     BOOL done = FALSE;
  502.     struct HoleArg *arg;
  503.  
  504.     /* Try to delete anything that we can get without prompting the user */
  505.     allow_request (FALSE);
  506.     for (arg = list->lh_Head; arg->node.ln_Succ; arg = arg->node.ln_Succ)
  507.     {
  508.     if (!delete (arg))  /* Returns 0 for success */
  509.     {
  510.         done = TRUE; break;
  511.     }
  512.     }
  513.     allow_request (TRUE);
  514.  
  515.     /* If that didn't work, just try first on the list */
  516.     arg = (struct HoleArg *)list->lh_Head;
  517.     until (done)
  518.     {
  519.     if (error = delete ((struct HoleArg *) arg))
  520.     {
  521.         if (user_request (error)) continue; /* user says Retry */
  522.         else
  523.         {                /* User says Cancel */
  524.         done = TRUE; break;
  525.         }
  526.     }
  527.     else done = TRUE;
  528.     }
  529.  
  530.     /* Now remove and free the arg */
  531.     Remove ((struct Node *)arg);
  532.     free_arg (arg);
  533. }
  534.  
  535. /* Add filenames from WBArg to the list, copying prefs etc... */
  536. /* Tries to minimise disk swapping */
  537. void copy_and_add (struct List *list, int argnum, struct WBArg *arglist)
  538. {
  539.     if (argnum > currprefs.deletelimit)
  540.     {
  541.     fail_request ("Warning:\nYou are trying to\ndelete too much");
  542.     return;
  543.     }
  544.  
  545.     struct List *tlist; /* temporary list before we have confirmed */
  546.     unless (tlist = malloc (sizeof (struct List))) goto fail;
  547.     NewList (tlist);
  548.     int lastarg = argnum;
  549.     LONG error = 0;
  550.  
  551.     BOOL firsttimeround = TRUE;
  552.     BOOL requesters;            /* flag saying whether requesters are on */
  553.  
  554.     int i;
  555.     for (i=0; lastarg; )
  556.     {
  557.     if (!i) requesters = TRUE;  /* If we have started the second round, */
  558.                     /* allow requesters to be put up.        */
  559.     if (i || firsttimeround)
  560.     {                /* otherwise requesters are not allowed */
  561.         requesters = FALSE;
  562.         firsttimeround = FALSE;
  563.     }
  564.     allow_request (requesters);
  565.  
  566.     /* We always add the first arg on the list, because we swap around */
  567.     unless (error = add_WBArg_to_List (&arglist[0], tlist))
  568.     {
  569.         /* everything worked, so swap the used arg to the end */
  570.         {    /* and reduce lastarg so that we don't see it again */
  571.         lastarg--;
  572.         struct WBArg targ = arglist [lastarg];
  573.         arglist [lastarg] = arglist[0];
  574.         arglist [0] = targ;
  575.         }
  576.     }
  577.     else
  578.     {
  579.         if (!requesters)
  580.         {    /* Some error has occurred but we haven't told the user about it */
  581.         /* Put off sorting it out till later by moving arg to the end. */
  582.         struct WBArg targ = arglist [lastarg-1];
  583.         arglist [lastarg-1] = arglist[0];
  584.         arglist [0] = targ;
  585.         }
  586.         else /* An error occurred so put up a requester for it */
  587.         {
  588.         /* If user presses retry then try again */
  589.         if (user_request(error)) continue;
  590.         else goto fail;
  591.         }
  592.     }
  593.  
  594.     i++;
  595.     if ((i == argnum) && lastarg)
  596.     {   /* We've tried all the args, but some have failed */
  597.         i = 0; /* back to the start again, this time requesters will be ok */
  598.     }
  599.     }
  600.  
  601.     unless (confirm_deletion (tlist)) goto fail;
  602.  
  603.     until (IsListEmpty (tlist))
  604.     {
  605.     /* Move contents of tlist to list */
  606.     AddTail (list, RemHead (tlist));
  607.     }
  608.  
  609.     fail:
  610.  
  611.     allow_request (TRUE);
  612.     free_list (tlist);      /* Only does anything if something failed */
  613.     if (tlist) free (tlist);   /* free the memory */
  614. }
  615.  
  616. LONG add_WBArg_to_List (struct WBArg *arg, struct List *list)
  617. {
  618.     struct HoleArg *holearg;
  619.     LONG error = 0;
  620.  
  621.     unless (holearg = create_arg()) return (ERROR_NO_FREE_STORE);
  622.     unless (holearg->wbarg.wa_Name = strdup (arg->wa_Name)) goto fail;
  623.  
  624.     unless (holearg->wbarg.wa_Lock = DupLock (arg->wa_Lock))
  625.     {
  626.     error = IoErr();
  627.     goto fail;
  628.     }
  629.  
  630.     if (currprefs.confirm)  /* put name of file into truncname */
  631.     {
  632.     set_current (NULL, SET_START);
  633.     if (error = set_current (&(holearg->wbarg), SET_NEWFILE)) goto fail;
  634.     unless (holearg->truncname = strdup (current))
  635.     {
  636.         error = ERROR_NO_FREE_STORE;
  637.         goto fail;
  638.     }
  639.     }
  640.  
  641.     holearg->prefs = currprefs;  /* put current prefs into arg */
  642.  
  643.     AddTail (list, (struct Node *)holearg);
  644.     return (0);
  645.  
  646.     fail:
  647.  
  648.     free_arg (holearg);
  649.     return (error);
  650. }
  651.  
  652. void free_list (struct List *list)
  653. {
  654.     unless (list) return;
  655.     until (IsListEmpty (list)) free_arg ((struct HoleArg *)RemTail (list));
  656. }
  657.  
  658. void free_arg (struct HoleArg *arg)
  659. {
  660.     unless (arg) return;
  661.  
  662.     if (arg->truncname) free (arg->truncname);
  663.     if (arg->wbarg.wa_Name) free (arg->wbarg.wa_Name);
  664.     UnLock (arg->wbarg.wa_Lock);
  665.     free (arg);
  666. }
  667.  
  668. /* reserve memory for a HoleArg, returning a pointer to it or NULL if failed */
  669. struct HoleArg *create_arg (void)
  670. {
  671.     struct HoleArg *arg;
  672.     unless (arg = calloc (1, sizeof (struct HoleArg))) return (NULL);
  673.     return (arg);
  674. }
  675.  
  676. void scrub (struct DiskObject *dob) /* RKM recommends you do this */
  677. {
  678.     dob->do_Magic = NULL;
  679.     dob->do_Version = NULL;
  680.     dob->do_Gadget.NextGadget = NULL;
  681.     dob->do_Gadget.LeftEdge = NULL;
  682.     dob->do_Gadget.TopEdge = NULL;
  683.     dob->do_Gadget.Activation = NULL;
  684.     dob->do_Gadget.GadgetType = NULL;
  685.     dob->do_Gadget.GadgetText = NULL;
  686.     dob->do_Gadget.MutualExclude = NULL;
  687.     dob->do_Gadget.SpecialInfo = NULL;
  688.     dob->do_Gadget.GadgetID = NULL;
  689.     dob->do_Gadget.UserData = NULL;
  690.     dob->do_Type = NULL;
  691.     dob->do_DefaultTool = NULL;
  692.     dob->do_CurrentX = currprefs.CurrentX;  /* set up position of icon */
  693.     dob->do_CurrentY = currprefs.CurrentY;
  694.     dob->do_ToolTypes = NULL;
  695.     dob->do_DrawerData = NULL;
  696.     dob->do_ToolWindow = NULL;
  697.     dob->do_StackSize = NULL;
  698. }                   /* Yaaaaaaawn! */
  699.  
  700. /* safe version of strncat that will not write over edge of dest buffer */
  701. char *safecat (char *dest, char *source, int destlen)
  702. {
  703.     int num = destlen - strlen(dest);
  704.     if (num <= 0) return (0);
  705.  
  706.     return (strncat (dest, source, num));
  707. }
  708.  
  709. /* Get rid of Please Insert Volume ... requester */
  710. void allow_request (BOOL allow)
  711. {
  712.     struct Process *proc;
  713.     proc = (struct Process *)FindTask (NULL);
  714.  
  715.     if (!allow && !old_window_ptr)
  716.     {
  717.     old_window_ptr = proc->pr_WindowPtr;
  718.     proc->pr_WindowPtr = (APTR)-1;
  719.     }
  720.     if (allow && (proc->pr_WindowPtr == (APTR)-1))
  721.     {
  722.     proc->pr_WindowPtr = old_window_ptr;
  723.     old_window_ptr = NULL;
  724.     }
  725. }
  726.  
  727. #define TEXT_LEN 768
  728.  
  729. /* returns TRUE if user says it's ok to delete */
  730. /* Relies on arg->truncname being filled in previously */
  731. BOOL confirm_deletion (struct List *tlist)
  732. {
  733.     unless (currprefs.confirm) return (TRUE);
  734.  
  735.     char text[TEXT_LEN+1];
  736.     char buf[40];
  737.     char *end;
  738.     struct HoleArg *arg;
  739.     BOOL isdir = FALSE;
  740.     int dirs = 0, files = 0;
  741.  
  742.     text[0] = (char)0;
  743.     safecat (text, "Delete the following?\n", TEXT_LEN);
  744.  
  745.     for (arg = tlist->lh_Head; arg->node.ln_Succ; )
  746.     {
  747.     end = arg->truncname + strlen (arg->truncname) -1;
  748.     if (*end == '/')
  749.     {
  750.         dirs++;
  751.         isdir = TRUE;
  752.         *end = 0;        /* remove trailing slash */
  753.     }
  754.     else
  755.     {
  756.         files++;
  757.         isdir = FALSE;
  758.     }
  759.  
  760.     safecat (text, arg->truncname, TEXT_LEN);
  761.     if (isdir)
  762.     {
  763.         safecat (text, " (drawer)", TEXT_LEN);
  764.         *end = '/';     /* restore what we altered */
  765.     }
  766.     safecat (text, "\n", TEXT_LEN);
  767.  
  768.     /* this must go here since there is a continue statement */
  769.     arg=arg->node.ln_Succ;    /* goto next arg */
  770.     }
  771.  
  772.     if (files)
  773.     {
  774.     if (dirs)
  775.     {
  776.         sprintf (buf, "(%d file%s and %d drawer%s)",
  777.         files,    (files == 1) ? "" : "s",
  778.         dirs,    (dirs == 1) ? "" : "s");
  779.     }
  780.     else sprintf (buf, "(%d file%s)", files, (files == 1) ? "" : "s");
  781.     }
  782.     else sprintf (buf, "(%d drawer%s)", dirs, (dirs == 1) ? "" : "s");
  783.     safecat (text, buf, TEXT_LEN);
  784.  
  785.     return (error_request (text, "Ok|Cancel"));
  786. }
  787.  
  788. #define BUF_LEN 255
  789.  
  790. BOOL user_request (LONG error)
  791. {
  792.     char buf[BUF_LEN+1], fault[FAULT_MAX+1];
  793.     char *end;
  794.  
  795.     strcpy (buf, "Error while deleting\n");
  796.     safecat (buf, current, BUF_LEN);    /* put in name of file being deleted */
  797.  
  798.     end = buf + strlen(buf) -1;
  799.     if (*end == '/') *end = 0;  /* if buf has trailing slash remove it */
  800.  
  801.     if (strcmp (buf, "")) safecat (buf, " :\n", BUF_LEN);  /* punctuation */
  802.  
  803.     Fault (error, "", fault, FAULT_MAX);   /* get error message from dos. */
  804.     fault[2] = toupper ((unsigned char)fault[2]);   /* capitalise 1st letter */
  805.  
  806.     safecat (buf, fault + 2, BUF_LEN);  /* copy removing ": " at head of message */
  807.     safecat (buf, ".", BUF_LEN);        /* finish the sentence */
  808.  
  809.     return (error_request (buf, "Retry|Cancel"));
  810. }
  811.  
  812.